"""
文本比较核心模块
提供文本差异比较功能
"""

import difflib
from typing import List, Dict, Tuple, Optional
from dataclasses import dataclass


@dataclass
class DiffResult:
    """差异比较结果"""
    line_number: int
    line_type: str  # 'added', 'removed', 'unchanged'
    content: str
    original_line: Optional[str] = None


class TextComparator:
    """文本比较器"""
    
    def __init__(self):
        self.ignore_case = False
        self.ignore_whitespace = False
        self.ignore_empty_lines = False
    
    def compare_texts(self, text1: str, text2: str) -> Dict[str, any]:
        """
        比较两个文本
        
        Args:
            text1: 第一个文本
            text2: 第二个文本
        
        Returns:
            比较结果字典
        """
        # 预处理文本
        processed_text1 = self._preprocess_text(text1)
        processed_text2 = self._preprocess_text(text2)
        
        # 分割为行
        lines1 = processed_text1.splitlines(keepends=True)
        lines2 = processed_text2.splitlines(keepends=True)
        
        # 使用difflib进行行级比较
        matcher = difflib.SequenceMatcher(None, lines1, lines2)
        
        # 生成差异
        diff_result = []
        for tag, i1, i2, j1, j2 in matcher.get_opcodes():
            if tag == 'equal':
                # 相同的行
                for line_num in range(i1, i2):
                    diff_result.append(DiffResult(
                        line_number=line_num + 1,
                        line_type='unchanged',
                        content=lines1[line_num].rstrip('\n')
                    ))
            elif tag == 'replace':
                # 替换的行
                for line_num in range(i1, i2):
                    diff_result.append(DiffResult(
                        line_number=line_num + 1,
                        line_type='removed',
                        content=lines1[line_num].rstrip('\n')
                    ))
                for line_num in range(j1, j2):
                    diff_result.append(DiffResult(
                        line_number=line_num + 1,
                        line_type='added',
                        content=lines2[line_num].rstrip('\n')
                    ))
            elif tag == 'delete':
                # 删除的行
                for line_num in range(i1, i2):
                    diff_result.append(DiffResult(
                        line_number=line_num + 1,
                        line_type='removed',
                        content=lines1[line_num].rstrip('\n')
                    ))
            elif tag == 'insert':
                # 插入的行
                for line_num in range(j1, j2):
                    diff_result.append(DiffResult(
                        line_number=line_num + 1,
                        line_type='added',
                        content=lines2[line_num].rstrip('\n')
                    ))
        
        # 统计信息
        stats = self._calculate_stats(diff_result)
        
        return {
            'diff_result': diff_result,
            'statistics': stats,
            'similarity_ratio': matcher.ratio()
        }
    
    def _preprocess_text(self, text: str) -> str:
        """预处理文本"""
        if self.ignore_case:
            text = text.lower()
        
        if self.ignore_whitespace:
            # 保留换行符，但去除行内多余空格
            lines = text.splitlines()
            lines = [' '.join(line.split()) for line in lines]
            text = '\n'.join(lines)
        
        if self.ignore_empty_lines:
            lines = text.splitlines()
            lines = [line for line in lines if line.strip()]
            text = '\n'.join(lines)
        
        return text
    
    def _calculate_stats(self, diff_result: List[DiffResult]) -> Dict[str, int]:
        """计算统计信息"""
        stats = {
            'total_lines': len(diff_result),
            'added_lines': 0,
            'removed_lines': 0,
            'unchanged_lines': 0
        }
        
        for result in diff_result:
            if result.line_type == 'added':
                stats['added_lines'] += 1
            elif result.line_type == 'removed':
                stats['removed_lines'] += 1
            elif result.line_type == 'unchanged':
                stats['unchanged_lines'] += 1
        
        return stats
    
    def generate_unified_diff(self, text1: str, text2: str, 
                            from_file: str = "file1", to_file: str = "file2") -> str:
        """生成统一格式的差异"""
        lines1 = text1.splitlines(keepends=True)
        lines2 = text2.splitlines(keepends=True)
        
        diff = difflib.unified_diff(
            lines1, lines2,
            fromfile=from_file,
            tofile=to_file,
            lineterm=''
        )
        
        return '\n'.join(diff)
    
    def generate_html_diff(self, text1: str, text2: str) -> str:
        """生成HTML格式的差异"""
        lines1 = text1.splitlines(keepends=True)
        lines2 = text2.splitlines(keepends=True)
        
        differ = difflib.HtmlDiff()
        html_diff = differ.make_file(lines1, lines2)
        
        return html_diff
    
    def compare_char_by_char(self, text1: str, text2: str) -> List[Dict[str, any]]:
        """字符级比较"""
        matcher = difflib.SequenceMatcher(None, text1, text2)
        char_diff = []
        
        for tag, i1, i2, j1, j2 in matcher.get_opcodes():
            if tag == 'equal':
                char_diff.append({
                    'type': 'unchanged',
                    'start': i1,
                    'end': i2,
                    'content': text1[i1:i2]
                })
            elif tag == 'replace':
                char_diff.append({
                    'type': 'removed',
                    'start': i1,
                    'end': i2,
                    'content': text1[i1:i2]
                })
                char_diff.append({
                    'type': 'added',
                    'start': j1,
                    'end': j2,
                    'content': text2[j1:j2]
                })
            elif tag == 'delete':
                char_diff.append({
                    'type': 'removed',
                    'start': i1,
                    'end': i2,
                    'content': text1[i1:i2]
                })
            elif tag == 'insert':
                char_diff.append({
                    'type': 'added',
                    'start': j1,
                    'end': j2,
                    'content': text2[j1:j2]
                })
        
        return char_diff
    
    def find_similar_lines(self, text1: str, text2: str, 
                          similarity_threshold: float = 0.8) -> List[Tuple[int, int, float]]:
        """查找相似的行"""
        lines1 = text1.splitlines()
        lines2 = text2.splitlines()
        
        similar_lines = []
        
        for i, line1 in enumerate(lines1):
            for j, line2 in enumerate(lines2):
                similarity = difflib.SequenceMatcher(None, line1, line2).ratio()
                if similarity >= similarity_threshold:
                    similar_lines.append((i + 1, j + 1, similarity))
        
        # 按相似度排序
        similar_lines.sort(key=lambda x: x[2], reverse=True)
        
        return similar_lines
    
    def merge_texts(self, text1: str, text2: str, merge_strategy: str = 'smart') -> str:
        """合并两个文本"""
        if merge_strategy == 'append':
            return text1 + '\n' + text2
        elif merge_strategy == 'prepend':
            return text2 + '\n' + text1
        elif merge_strategy == 'smart':
            # 智能合并：去除重复行
            lines1 = set(text1.splitlines())
            lines2 = set(text2.splitlines())
            
            # 保留text1的所有行，添加text2中不重复的行
            merged_lines = list(lines1)
            for line in lines2:
                if line not in lines1:
                    merged_lines.append(line)
            
            return '\n'.join(merged_lines)
        else:
            return text1
    
    def set_comparison_options(self, ignore_case: bool = False, 
                              ignore_whitespace: bool = False, 
                              ignore_empty_lines: bool = False):
        """设置比较选项"""
        self.ignore_case = ignore_case
        self.ignore_whitespace = ignore_whitespace
        self.ignore_empty_lines = ignore_empty_lines 